package volkov.ja.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class PageUtils {

	private static int expLTimeout = 15;

	private WebDriver webDriver;

	public PageUtils(WebDriver webdriver) {
		this.webDriver = webdriver;
	}

	public void handleAlertIfPresent(boolean accept, String errorMsg) {
		try {
			(new WebDriverWait(webDriver, expLTimeout))
					.until(ExpectedConditions.alertIsPresent());
		} catch (TimeoutException e) {
			throw new MyProjectException(errorMsg);
		}
		Alert alert = webDriver.switchTo().alert();
		if (accept) {
			alert.accept();
		} else {
			alert.dismiss();
		}
	}

	public WebElement checkElementWithContent(By by, String content,
			String errorMsg) {
		boolean found = false;
		WebElement out = null;
		List<WebElement> elements = getElementsIfPresent(by);
		for (WebElement we : elements) {
			try {
				if (we.getText().equals(content)
						|| (we.getAttribute("value") != null && we
								.getAttribute("value").equals(content))) {
					found = true;
					out = we;
				}
			} catch (StaleElementReferenceException e) {
				e.printStackTrace();
			}
		}
		if (!found) {
			throw new MyProjectException(errorMsg);
		}
		return out;
	}

	private List<WebElement> getElementsIfPresent(By by) {
		try {
			return (new WebDriverWait(webDriver, expLTimeout))
					.until(ExpectedConditions
							.presenceOfAllElementsLocatedBy(by));
		} catch (TimeoutException e) {
			return Collections.<WebElement> emptyList();
		}
	}

	public void checkElementIsAbsent(By by, String msg) {
		try {
			// throws exception if finds nothing
			webDriver.findElement(by);
			// unreachable if an exception is thrown
			throw new MyProjectException(msg);
		} catch (NoSuchElementException e) {
			return;
		}
	}

	public void clickIfPresent(By by) {
		WebElement we = null;
		try {
			we = (new WebDriverWait(webDriver, expLTimeout))
					.until(ExpectedConditions.elementToBeClickable(by));
		} catch (TimeoutException e) {
			// nothing to do here
		}
		if (we != null) {
			we.click();
		}
	}

	public WebElement getUpdatedElement(By by, WebElement old, String errorMsg) {
		try {
			(new WebDriverWait(webDriver, expLTimeout))
					.until(ExpectedConditions.stalenessOf(old));
		} catch (TimeoutException e) {
			throw new MyProjectException(errorMsg
					+ " :: old WebElement was not updated");
		}
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		WebElement we = null;
		try {
			we = webDriver.findElement(by);
		} catch (NoSuchElementException e) {
			throw new MyProjectException(errorMsg
					+ " :: updated WebElement is not present any more");
		}
		return we;
	}

	public List<WebElement> getElementsHavingChildWithContent(
			final By byParent, final By byChild, final String content,
			final boolean partialSearch) {
		List<WebElement> wes = Collections.emptyList();
		try {
			wes = (new WebDriverWait(webDriver, expLTimeout))
					.until(new ExpectedCondition<List<WebElement>>() {
						public List<WebElement> apply(WebDriver d) {
							List<WebElement> out = new ArrayList<WebElement>();
							List<WebElement> parents = d.findElements(byParent);
							int size = -1;
							while (parents.size() > size) {
								size = parents.size();
								try {
									Thread.sleep(200);
								} catch (InterruptedException e1) {
									e1.printStackTrace();
								}
								parents = d.findElements(byParent);
							}
							// TODO: do it quicker
							for (WebElement parent : parents) {
								WebElement child = null;
								try {
									child = parent.findElement(byChild);
								} catch (NoSuchElementException e) {
									continue;
								}
								if (content != null) {
									if (partialSearch) {
										if (child
												.getText()
												.toLowerCase()
												.contains(content.toLowerCase())
												|| (child.getAttribute("value") != null && child
														.getAttribute("value")
														.toLowerCase()
														.contains(
																content.toLowerCase()))) {
											out.add(parent);
										} else {
											continue;
										}
									} else {
										if (child.getText().equalsIgnoreCase(
												content)
												|| (child.getAttribute("value") != null && child
														.getAttribute("value")
														.equalsIgnoreCase(
																content))) {
											out.add(parent);
										} else {
											continue;
										}
									}
								} else {
									out.add(parent);
								}
							}
							return out.isEmpty() ? null : out;
						}
					});
		} catch (TimeoutException e) {
			// nothing to do here
			// throw new MyProjectException(
			// errorMsg
			// + " :: "
			// + "No elements \""
			// + byParent
			// + "\" found with a child \""
			// + byChild
			// + "\""
			// + (content != null ? " containing \"" + content
			// + "\"" : ""));
		}
		return wes;
	}
}
